<?php
declare (strict_types=1);

namespace app\listener;

use app\common\job\LawyerResponseStatistics;
use app\common\model\Consulting;
use app\common\model\ConsultingMessage;
use app\common\model\ConsultingQuestion;
use app\common\model\ConsultingServer;
use app\common\model\Member;
use app\common\service\DouyinMiniProgramMessageService;
use app\common\service\MiniProgramMessageService;
use app\common\service\SubscriptionMessageService;
use app\common\service\TemplateSmsService;
use app\index\service\ConsultingServerService;
use app\index\service\MessageSendService;
use app\index\service\QuestionService;
use app\index\traits\ChatFreelyTrait;
use app\index\traits\MessageSendTrait;
use ShidianUtil\Concurrent\Synchronizer;
use ShidianUtil\Utils\CheckUtil;
use think\facade\Config;
use think\facade\Queue;

/**
 *
 * Class RandomConsultingMessageCreated
 * @package app\listener
 */
class RandomConsultingMessageCreated
{
    use ChatFreelyTrait;
    use MessageSendTrait;

    /**
     * 用户主动发送消息创建 事件监听处理
     *
     * @return mixed
     */
    public function handle($params)
    {
        $user = $params['user'] ?? null;
        $message = $params['message'] ?? null;
        $consulting = $params['consulting'] ?? null;

        $userType = $user->type;

        if ($userType == 0) {
            // 用户

            $this->handleOfMember($user, $message, $consulting);
        }

        if ($userType == 1) {
            // 律师

            $this->handleOfLawyer($user, $message, $consulting);
        }
    }

    /**
     * 处理用户消息
     * @param Member $user
     * @param ConsultingMessage $message
     * @param Consulting $consulting
     * @return void
     */
    private function handleOfMember(Member $user, ConsultingMessage $message, Consulting $consulting)
    {

        $userId = $user->id;
        $messageType = $message->messageType;
        $consultingId = $consulting->id;
        $robotId = $consulting->robotId;

        $contentStr = messageContentStr($messageType, $message->content);
        $now = time();

        // 绑定问题
        $bind = $this->questionBind($userId, $consultingId, $contentStr, $consulting);

        if ($bind) {
            // 首句提问

            // 发送机器人消息1
            $content = [
                'text' => '已收到您的咨询，正在为您匹配金牌律师请不要离开页面。'
            ];
            $this->getMessageSendService()->sendRobotMessage($consulting, $robotId, 0, ConsultingMessage::TEXT, $content);

            sleep(2);

            // 进度卡片
            $second = Config::get('consulting.match_second', 5);
            $content = [
                'millisecond' => $second * 1000,
                'str1' => '正在为您优先匹配',
                'str2' => '金牌律师',
            ];
            $message = $this->getMessageSendService()->sendSystemMessage($consulting, 0, ConsultingMessage::PROGRESS, $content);
            // 等几秒
            sleep($second);
            // 删除消息
            $this->getMessageSendService()->deleteMessage($message->id);

            // 进入下一阶段
            $consulting->step = 1;
            $consulting->save();

            // 触发咨询变动事件（更新前端的咨询模型）
            event('ConsultingUpdated', $consulting);

            // XX个律师愿意接单卡片 + 服务卡片
            $freeServer = ConsultingServer::where('id', $consulting->consultingServerId)->find();
            $this->sendLawyersAndRecommendServerMessage($consulting, $freeServer->recommendServerId);

            // TODO 改成付款后才匹配律师

            // 进入匹配律师流程
            // $this->getConsultingLawyerMatchV2Service()->matchRandom($consulting);

        } else {
            // 追问

            $isChatFreely = $this->isChatFreely($consulting);

            // 扣减次数
            if (!$isChatFreely && $consulting->questionsNum > 0) {

                $consulting->questionsNum = $consulting->questionsNum - 1;
                $consulting->save();

            }

            // 如果追问的时候存在律师，那么给律师发公众号模板消息
            if (is_id($consulting->lawyerId) && $consulting->rushStatus == 2) {
                $pagepath = 'pages/lawyer/lawyer?confirm_id='.$consulting->id;
                $this->getSubscriptionMessageService()->messageAsk($consulting->lawyerId, $user->nickname, $consulting->ask, $contentStr, $now, $pagepath);
            }

            // 判断次数
            if (!$isChatFreely && $consulting->questionsNum <= 0) {

                // 触发咨询变动事件（更新前端的咨询模型）
                event('ConsultingUpdated', $consulting);

                // 触发剩余次数不足
                event('ConsultingQuestionNumNotEnough', $consulting);
            }

        }

    }

    /**
     * 律师发送了消息
     * @param Member $user
     * @param ConsultingMessage $message
     * @param Consulting $consulting
     * @return void
     */
    private function handleOfLawyer(Member $user, ConsultingMessage $message, Consulting $consulting)
    {

        $realname = $user->realname;
        $consultingId = $consulting->id;
        $memberId = $consulting->memberId;
        $lawyerId = $consulting->lawyerId;
        $messageType = $message->messageType;
        $contentStr = messageContentStr($messageType, $message->content);
        $ask = $consulting->ask;
        $now = time();

        // 绑定答案
        $bind = $this->answerBind($consultingId, $consulting);

        if ($bind) {
            // 首句回复

            // 进入下一阶段
            $consulting->step = 2;
            $consulting->save();

            // 触发咨询变动事件（更新前端的咨询模型）
            event('ConsultingUpdated', $consulting);

            // 律师数据统计
            $job_data = ['id' => $lawyerId];
            Queue::push(LawyerResponseStatistics::class, $job_data);

            // 律师首次回答，尝试激活免费服务
            if ($consulting->consultingType == '0') {
                $this->getConsultingServerService()->serverStartOfFree($consultingId, $consulting->consultingServerId);
            }

            // 律师首次回答，给用户发短信通知
            $phone = Member::where('id', $memberId)->value('phone');
            if (CheckUtil::isPhoneNumber($phone)) {
                $this->getTemplateSmsService()->lawyerReply2($phone, $ask, $realname, $consultingId);
            }
        }


        // 微信小程序订阅消息
        $this->getMiniProgramMessageService()->messageLawyerFirstReplay($memberId, $contentStr, $realname, $now);

        // 抖音小程序订阅消息
        $this->getDouyinMiniProgramMessageService()->messageLawyerFirstReplay($memberId, $contentStr, $realname, $now);
    }

    /**
     * 绑定答案
     * @param $consultingId
     * @param $consulting
     * @return bool
     */
    private function answerBind($consultingId, &$consulting): bool
    {
        $bind = false;

        $signature = __CLASS__ . $consultingId;
        $this->getSynchronizer()->synchronized($signature, function () use (&$bind, &$consulting, $consultingId) {

            $consulting = Consulting::where('id', $consultingId)->find();

            // 置为已回答
            if ($consulting->isAnswered == '0') {
                $consulting->isAnswered = '1';
                $consulting->rushStatus = '2';
                $consulting->responseTimeLength = time() - $consulting->rushTime;
                $consulting->save();

                $bind = true;
            }
        });

        return $bind;
    }

    /**
     * 绑定问题
     * @param int $userId
     * @param int $consultingId
     * @param string $contentStr
     * @param $consulting
     * @return bool 是否绑定问题
     */
    private function questionBind(int $userId, int $consultingId, string $contentStr, &$consulting): bool
    {
        $first = false;

        $signature = __CLASS__ . $consultingId;
        $this->getSynchronizer()->synchronized($signature, function () use (&$first, &$consulting, $contentStr, $userId, $consultingId) {

            $consulting = Consulting::where('id', $consultingId)->find();

            if ($consulting->isAsked == '0') {
                // 首句提问

                $first = true;

                // 生成问题
                $question = $this->getQuestionService()->saveQuestion($userId, $contentStr, '0', '', ConsultingQuestion::FROM_CONSULTING, true,
                    '', $consulting->pf, $consulting->chain, $consulting->promotionGroupId);

                // 绑定问题
                $consulting->isAsked = '1';
                $consulting->ask = $question->ask;
                $consulting->questionId = $question->id;
                $consulting->save();

            }
        });

        return $first;
    }

    private function getQuestionService(): QuestionService
    {
        return app(QuestionService::class);
    }

    private function getSynchronizer(): Synchronizer
    {
        return app(Synchronizer::class);
    }

    private function getSubscriptionMessageService(): SubscriptionMessageService
    {
        return app(SubscriptionMessageService::class);
    }

    private function getMiniProgramMessageService(): MiniProgramMessageService
    {
        return app(MiniProgramMessageService::class);
    }

    private function getDouyinMiniProgramMessageService(): DouyinMiniProgramMessageService
    {
        return app(DouyinMiniProgramMessageService::class);
    }

    private function getTemplateSmsService(): TemplateSmsService
    {
        return app(TemplateSmsService::class);
    }

    private function getMessageSendService(): MessageSendService
    {
        return app(MessageSendService::class);
    }

    private function getConsultingServerService(): ConsultingServerService
    {
        return app(ConsultingServerService::class);
    }
}
